home *** CD-ROM | disk | FTP | other *** search
/ Explorer - Mosaic & Web / Explorer - Mosaic & Web.iso / helpers / ghostvew / src / gvcdsc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-01  |  32.5 KB  |  1,146 lines

  1. /* Copyright (C) 1993, 1994, Russell Lang.  All rights reserved.
  2.   
  3.   This file is part of GSview.
  4.   
  5.   This program is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the GSview Free Public Licence 
  9.   (the "Licence") for full details.
  10.   
  11.   Every copy of GSview must include a copy of the Licence, normally in a 
  12.   plain ASCII text file named LICENCE.  The Licence grants you the right 
  13.   to copy, modify and redistribute GSview, but only under certain conditions 
  14.   described in the Licence.  Among other things, the Licence requires that 
  15.   the copyright notice and this notice be preserved on all copies.
  16. */
  17.  
  18. /* gvcdsc.c */
  19. /* DSC scanning module */
  20.  
  21. /* tasks */
  22. /* %%BeginPaperSize: */
  23.  
  24.  
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <stdarg.h>
  28. #include <string.h>
  29. #include <ctype.h>
  30. #ifdef EPSTOOL
  31. #include "epstool.h"
  32. #else
  33. #define DWORD unsigned long    /* correct for OS/2 and MS-Windows */
  34. #define WORD unsigned short 
  35. #include "gvcdsc.h"
  36. #endif
  37.  
  38. /* known media types */
  39. PSMEDIA paper_size[34] = {
  40.     /* taken from gs_statd.ps */
  41.     /* which says that the following are defined in Adobe Documentation */
  42.     {"letter", 612, 792},
  43.     {"lettersmall", 612, 792},
  44.     {"note", 540, 720},
  45.     {"legal", 612, 1008},
  46.     {"11x17", 792, 1224},
  47.     {"ledger", 1224, 792},
  48.     {"a3", 842, 1190},
  49.     {"a4", 595, 842},
  50.     {"a4small", 595, 842},
  51.     {"b5", 501, 709},
  52.     /* extra media types from gs_statd.ps */
  53.     {"a0", 2380, 3368},    /* ISO standard */
  54.     {"a1", 1684, 2380},
  55.     {"a2", 1190, 1684},
  56.     {"a5", 421, 595},
  57.     {"a6", 297, 421},
  58.     {"a7", 210, 421},
  59.     {"a8", 148, 210},
  60.     {"a9", 105, 148},
  61.     {"a10", 74, 105},
  62.     {"b0", 2836, 4008},
  63.     {"b1", 2004, 2836},
  64.     {"b2", 1418, 2004},
  65.     {"b3", 1002, 1418},
  66.     {"b4", 501, 709},
  67.     {"archE", 2592, 3456},    /* US CAD */
  68.     {"archD", 1728, 2592},
  69.     {"archC", 1296, 1728},
  70.     {"archB", 864, 1296},
  71.     {"archA", 648, 864},
  72.     {"flsa", 612, 936},     /* US foolscap */
  73.     {"flse", 612, 936},     /* European foolscap */
  74.     {"halfletter", 396, 612},
  75.     {"tabloid", 792, 1224},    /* 11x17 */
  76.     {NULL, 0, 0}
  77. };
  78.  
  79. #define TRUE 1
  80. #define FALSE 0
  81.  
  82. /* globals */
  83. static int debug;
  84.  
  85. /* print an error message */
  86. /* we do it this way so we can write output into a message box under */
  87. /* windowing environment such as MS-Windows or OS/2 PM */
  88. static int
  89. eprintf(char *fmt, ...)
  90. {
  91. int count;
  92. va_list args;
  93.     va_start(args, fmt);
  94. #ifdef COMMANDLINE
  95.     count = vfprintf(stderr, fmt, args);
  96.     count += fprintf(stderr, "\n");
  97. #else
  98.     {
  99.         char buf[256];
  100.         count = vsprintf(buf, fmt, args);
  101.         pserror(buf);    /* pserror must be provided by application linking with gvcdsc.c */
  102.     }
  103. #endif
  104.     va_end(args);
  105.     return count;
  106. }
  107.  
  108. #ifdef DEBUG
  109. void *mymalloc(int length)
  110. {
  111. void *p;
  112.     if (debug)
  113.         eprintf("mymalloc: length=%d, ",length);
  114.     p = malloc(length);
  115.     if (debug)
  116.         eprintf("pointer=%p\n",p);
  117.     return p;
  118. }
  119. #define malloc(len) mymalloc(len)
  120. #endif
  121.  
  122. static int
  123. nomemory(char *fname, int sline)
  124. {
  125.     eprintf("gvcdsc.c: out of memory at %s:%d", fname, sline);
  126.     return FALSE;
  127. }
  128.  
  129. /* Get next line, skipping over data and included documents */
  130. static int
  131. getline(PSDOC *psdoc)
  132. {
  133.     psdoc->position = ftell(psdoc->f);
  134.     if (psdoc->enddoseps && (psdoc->position >= psdoc->enddoseps)) {
  135.         psdoc->line[0] = '\0';
  136.         return FALSE;    /* have reached end of DOSEPS ps section */
  137.     }
  138.     if (fgets(psdoc->line, PSLINELENGTH, psdoc->f)) {
  139.         psdoc->linecount++;
  140.         /* skip over binary sections */
  141.         if (strncmp(psdoc->line, "%%BeginBinary:",14)==0) {
  142.         long count = 0;
  143.         int read;
  144.         char buf[1024];
  145.         if (sscanf(psdoc->line+14, "%ld", &count) != 1)
  146.             count = 0;
  147.         while (count) {
  148.             read = fread(buf, 1, sizeof(buf), psdoc->f);
  149.             count -= read;
  150.             if (read == 0)
  151.                 count = 0;
  152.         }
  153.         }
  154.         if (strncmp(psdoc->line, "%%BeginData:",12)==0) {
  155.             long count;
  156.             int read;
  157.             char buf[PSLINELENGTH];
  158.             if (sscanf(psdoc->line+12, "%ld %*s %s", &count, buf) != 2)
  159.                 count = 0;
  160.             if (strncmp(buf, "Lines", 5) == 0) {
  161.                 while (count) {
  162.                     count--;
  163.             do {    /* handle antisocial PostScript with excessively long lines */
  164.                 if (fgets(buf, sizeof(buf), psdoc->f) == (char *)NULL) {
  165.                     count = 0;
  166.                 buf[0] = '\0';
  167.                 }
  168.             } while ( (strlen(buf) == sizeof(buf)-1) &&
  169.                       (buf[sizeof(buf)-2] != '\n') );
  170.             psdoc->linecount++;
  171.                 }
  172.             }
  173.             else {
  174.             while (count) {
  175.             read = fread(buf, 1, sizeof(buf), psdoc->f);
  176.             count -= read;
  177.             if (read == 0)
  178.                 count = 0;
  179.             }
  180.             }
  181.         }
  182.         /* skip over included documents */
  183.         if (strncmp(psdoc->line, "%%BeginDocument:",16)==0) {
  184.         while (strncmp(psdoc->line,"%%EndDocument",13)!=0) {
  185.             if (!getline(psdoc))
  186.             return FALSE;
  187.         }
  188.         }
  189.         return TRUE;
  190.     }
  191.     return FALSE;
  192. }
  193.  
  194. /* remove trailing \r and \n */
  195. static void
  196. stripline(char *line)
  197. {
  198. char *p;
  199.     if ( (p=strchr(line, '\r')) != (char *)NULL )
  200.         *p = '\0';
  201.     if ( (p=strchr(line, '\n')) != (char *)NULL )
  202.         *p = '\0';
  203. }
  204.  
  205. /* copy backslashed character to dest */
  206. /* return pointer to last character of backslash sequence */
  207. char *
  208. dsc_escape(char *source, char *dest)
  209. {
  210.     source++;    /* skip over backslash */
  211.     if (isdigit(*source)) {
  212.         *dest = (char)(*source-'0');
  213.         source++;
  214.         if (isdigit(*source)) {
  215.             *dest = (char)((*dest<<3) + (*source-'0'));
  216.             source++;
  217.         if (isdigit(*source)) {
  218.             *dest = (char)((*dest<<3) + (*source-'0'));
  219.         }
  220.         }
  221.     }
  222.     else if (*source == 'n') {
  223.         *dest = '\n';
  224.     }
  225.     else if (*source == 'r') {
  226.         *dest = '\r';
  227.     }
  228.     else if (*source == 't') {
  229.         *dest = '\t';
  230.     }
  231.     else {
  232.         *dest = *source;
  233.     }
  234.     return source;
  235. }
  236.  
  237. /* copy text from s to d, dealing with (), "", \octal */
  238. /* return pointer to next text item in n */
  239. /* return number of characters copied */
  240. int
  241. dsc_text(char *s, char *d, char **n)
  242. {
  243. int paren = 0;
  244. int count = 0;
  245.     *d = '\0';
  246.     /* skip over leading white space */
  247.     while (*s && ((*s==' ') || (*s=='\t')))
  248.        s++;
  249.     if (*s == '(') {
  250.         /* delimited by () */
  251.         s++;
  252.         while (*s && ((*s!=')') || paren!=0)) {
  253.         if (*s == '\\') {
  254.             s = dsc_escape(s, d);
  255.         }
  256.         else {
  257.             if (*s == '(')
  258.                 paren++;
  259.             if (*s == ')')
  260.                 paren--;
  261.             *d = *s;
  262.         }
  263.         s++;
  264.         d++;
  265.         count++;
  266.         }
  267.     }
  268.     else if (*s == '"') {
  269.         /* delimited by "" */
  270.         s++;
  271.         while (*s && *s!='"') {
  272.         if (*s == '\\') {
  273.             s = dsc_escape(s, d);
  274.         }
  275.         else {
  276.             *d = *s;
  277.         }
  278.         s++;
  279.         d++;
  280.         count++;
  281.         }
  282.     }
  283.     else {
  284.         while (*s && *s!=' ' && *s!='\t') {
  285.         if (*s == '\\') {
  286.             s = dsc_escape(s, d);
  287.         }
  288.         else {
  289.             *d = *s;
  290.         }
  291.         s++;
  292.         d++;
  293.         count++;
  294.         }
  295.     }
  296.     *d = '\0';
  297.     if (*s != '\0') {
  298.         *s++ = '\0';
  299.         while (*s && ((*s==' ') || (*s=='\t')))
  300.            s++;
  301.     }
  302.     *n = s;
  303.     return count;
  304. }
  305.  
  306. static PSDOC *
  307. cleanup(PSDOC *psdoc)
  308. {
  309.     if (psdoc) {
  310.         if (psdoc->firstline)
  311.         free(psdoc->firstline);
  312.         if (psdoc->title)
  313.         free(psdoc->title);
  314.         if (psdoc->date)
  315.         free(psdoc->date);
  316.         if (psdoc->page_list) {
  317.         PSPAGE  *pspage, *nextpage;
  318.         for (pspage = psdoc->page_list; pspage != (PSPAGE *)NULL; 
  319.             pspage = nextpage) {
  320.             nextpage = pspage->next;
  321.             free(pspage);
  322.         }
  323.         }
  324.         if (psdoc->pages)
  325.         free(psdoc->pages);
  326.         if (psdoc->doseps)
  327.         free(psdoc->doseps);
  328.         if (psdoc->document_media) {
  329.         PSMEDIA  *media, *nextmedia;
  330.         for (media = psdoc->document_media; media != (PSMEDIA *)NULL; 
  331.             media = nextmedia) {
  332.                 if (media->name)
  333.                 free(media->name);
  334.             nextmedia = media->next;
  335.             free(media);
  336.         }
  337.         }
  338.         if (psdoc->default_page_media) {
  339.             if (psdoc->default_page_media->name)
  340.             free(psdoc->default_page_media->name);
  341.         free(psdoc->default_page_media);
  342.         }
  343.         free(psdoc);
  344.     }
  345.     return (PSDOC *)NULL;
  346. }
  347.  
  348. static int
  349. dsc_nextsection(PSDOC *psdoc)
  350. {
  351.     if (strncmp(psdoc->line, "%%BeginPreview:", 15) == 0) {
  352.         return TRUE;
  353.     }
  354.     else if (strncmp(psdoc->line, "%%BeginDefaults", 15) == 0) {
  355.         return TRUE;
  356.     }
  357.     else if (strncmp(psdoc->line, "%%BeginProlog", 13) == 0) {
  358.         return TRUE;
  359.     }
  360.     else if (strncmp(psdoc->line, "%%BeginSetup", 12) == 0) {
  361.         return TRUE;
  362.     }
  363.     else if (strncmp(psdoc->line, "%%Page:", 7) == 0) {
  364.         return TRUE;
  365.     }
  366.     else if (strncmp(psdoc->line, "%%Trailer", 9) == 0) {
  367.         return TRUE;
  368.     }
  369.     return FALSE;
  370. }
  371.  
  372. static int
  373. dsc_document_media(PSDOC *psdoc)
  374. {
  375.     float width, height;
  376.     PSMEDIA *media;
  377.     char name[PSLINELENGTH];
  378.     char *n;
  379.     dsc_text(psdoc->line+16, name, &n);
  380.     media = malloc(sizeof(PSMEDIA));
  381.     if (media == (PSMEDIA *)NULL)
  382.         return nomemory(__FILE__, __LINE__);
  383.     media->width = 0;
  384.     media->height = 0;
  385.     media->next = NULL;
  386.     media->name = malloc(strlen(name)+1);
  387.     if (media->name == (char *)NULL)
  388.         return nomemory(__FILE__, __LINE__);
  389.     strcpy(media->name, name);
  390.     if (sscanf(n, "%f %f", &width, &height) == 2) {
  391.         media->width  = (int)(width+0.5);
  392.         media->height = (int)(height+0.5);
  393.     }
  394.     else
  395.         eprintf("Incorrect %%%%DocumentMedia at line %d", psdoc->linecount);
  396.     psdoc->document_media = media;
  397.     while (getline(psdoc)) {
  398.         if (strncmp(psdoc->line, "%%+", 3) != 0)
  399.         break; /* not a continuation line */
  400.         dsc_text(psdoc->line+3, name, &n);
  401.         media->next = malloc(sizeof(PSMEDIA));
  402.         if (media->next == (PSMEDIA *)NULL)
  403.         return nomemory(__FILE__, __LINE__);
  404.         media = media->next;
  405.         media->width = 0;
  406.         media->height = 0;
  407.         media->next = NULL;
  408.         media->name = malloc(strlen(name)+1);
  409.         if (media->name == (char *)NULL)
  410.         return nomemory(__FILE__, __LINE__);
  411.         strcpy(media->name, name);
  412.         if (sscanf(n, "%f %f", &width, &height) == 2) {
  413.             media->width  = (int)(width+0.5);
  414.             media->height = (int)(height+0.5);
  415.         }
  416.         else
  417.         eprintf("Incorrect %%%%DocumentMedia at line %d", psdoc->linecount);
  418.     }
  419.     return TRUE;
  420. }
  421.  
  422. static int
  423. dsc_comments(PSDOC *psdoc)
  424. {
  425. char *p;
  426. int readahead = 0;
  427.     stripline(psdoc->line);
  428.     psdoc->begincomments = psdoc->position;
  429.     if (strncmp(psdoc->line, "\004%!PS-Adobe-",11)==0) {
  430.         psdoc->ctrld = TRUE;    /* for nasty MS-Windows output */
  431.         psdoc->begincomments++;
  432.     }
  433.     if ( (strncmp(psdoc->line, "%!PS-Adobe-",11)!=0) && !psdoc->ctrld )
  434.         return FALSE;    /* not DSC */
  435.     psdoc->firstline = malloc(strlen(psdoc->line)+1);
  436.     if (!psdoc->firstline)
  437.         return nomemory(__FILE__, __LINE__);
  438.     strcpy(psdoc->firstline, psdoc->line);
  439.     if (strstr(psdoc->line, "EPSF"))
  440.         psdoc->epsf = TRUE;
  441.     psdoc->endcomments = ftell(psdoc->f);
  442.     while (readahead || getline(psdoc)) {
  443.         readahead = FALSE;
  444.         if (strncmp(psdoc->line, "%%EndComments", 13) == 0) {
  445.         getline(psdoc);
  446.         psdoc->endcomments = psdoc->position;
  447.         break;
  448.         }
  449.         else if (strncmp(psdoc->line, "%%Begin", 7) == 0) {
  450.         break;    /* start of next section */
  451.         }
  452.         else if (strncmp(psdoc->line, "%%", 2) != 0) {
  453.         if (strlen(psdoc->line) < 2)
  454.            break;
  455.         if (psdoc->line[0] != '%')
  456.            break;
  457.         if ((psdoc->line[1] == ' ') || (psdoc->line[1] == '\t'))
  458.            break;
  459.         }
  460.         else if (strncmp(psdoc->line, "%%BoundingBox:", 14) == 0) {
  461.         if (strstr(psdoc->line + 14, "(atend)") != (char *)NULL) {
  462.             psdoc->bbox.valid = ATEND;
  463.         }
  464.         else {
  465.             if (sscanf(psdoc->line + 14, "%d %d %d %d", &psdoc->bbox.llx, &psdoc->bbox.lly,
  466.             &psdoc->bbox.urx, &psdoc->bbox.ury) == 4) {
  467.             psdoc->bbox.valid = TRUE;
  468.             }
  469.             else {
  470.             float llx, lly, urx, ury;
  471.                 if (sscanf(psdoc->line + 14, "%f %f %f %f", &llx, &lly, &urx, &ury) == 4) {
  472.                 psdoc->bbox.llx = (int)llx;
  473.                 psdoc->bbox.lly = (int)lly;
  474.                 psdoc->bbox.urx = (int)urx;
  475.                 psdoc->bbox.ury = (int)ury;
  476.                 psdoc->bbox.valid = TRUE;
  477.                     eprintf("Invalid %%%%BoundingBox on line %d.  Coodinates must be integers.", psdoc->linecount);
  478.                 }
  479.             else {
  480.                     eprintf("Invalid %%%%BoundingBox on line %d", psdoc->linecount);
  481.                     return FALSE;
  482.                 }
  483.             }
  484.         }
  485.         }
  486.         else if (strncmp(psdoc->line, "%%Pages:", 8) == 0) {
  487.         if (strstr(psdoc->line + 8, "(atend)") != (char *)NULL)
  488.             psdoc->dscpages = ATEND;
  489.         else {
  490.             if (sscanf(psdoc->line + 8, "%d", &psdoc->dscpages) != 1) {
  491.                 eprintf("Invalid %%%%Pages on line %d", psdoc->linecount);
  492.                 return FALSE;
  493.             }
  494.         }
  495.         }
  496.         else if (strncmp(psdoc->line, "%%Title:", 8) == 0) {
  497.         stripline(psdoc->line);
  498.         p = psdoc->line+8;
  499.         while (*p && (*p==' '))
  500.            p++;
  501.         psdoc->title = malloc(strlen(p)+1);
  502.         if (!psdoc->title)
  503.             return nomemory(__FILE__, __LINE__);
  504.         strcpy(psdoc->title, p);
  505.         }
  506.         else if (strncmp(psdoc->line, "%%CreationDate:", 15) == 0) {
  507.         stripline(psdoc->line);
  508.         p = psdoc->line+15;
  509.         while (*p && (*p==' '))
  510.            p++;
  511.         psdoc->date = malloc(strlen(p)+1);
  512.         if (!psdoc->date)
  513.             return nomemory(__FILE__, __LINE__);
  514.         strcpy(psdoc->date, p);
  515.         }
  516.         else if (strncmp(psdoc->line, "%%PageOrder:", 12) == 0) {
  517.         stripline(psdoc->line);
  518.         if ( (p = strtok(psdoc->line+12, " \t")) != (char *)NULL ) {
  519.             if (strcmp(p, "Ascend") == 0)
  520.             psdoc->pageorder = ASCEND;
  521.             else if (strcmp(p, "Descend") == 0)
  522.             psdoc->pageorder = DESCEND;
  523.             else if (strcmp(p, "Special") == 0)
  524.             psdoc->pageorder = SPECIAL;
  525.             else if (strcmp(p, "(atend)") == 0)
  526.             psdoc->pageorder = ATEND;
  527.             else
  528.                 eprintf("Unknown %%%%PageOrder on line %d", psdoc->linecount);
  529.         }
  530.         else
  531.                 eprintf("Unknown %%%%PageOrder on line %d", psdoc->linecount);
  532.         }
  533.         else if (strncmp(psdoc->line, "%%Orientation:", 14) == 0) {
  534.         stripline(psdoc->line);
  535.         if ( (p = strtok(psdoc->line+14, " \t")) != (char *)NULL ) {
  536.             if (strcmp(p, "Portrait") == 0)
  537.             psdoc->orientation = PORTRAIT;
  538.             else if (strcmp(p, "Landscape") == 0)
  539.             psdoc->orientation = LANDSCAPE;
  540.             else if (strcmp(p, "(atend)") == 0)
  541.             psdoc->orientation = ATEND;
  542.             else
  543.                 eprintf("Unknown %%%%Orientation on line %d", psdoc->linecount);
  544.         }
  545.         else
  546.                 eprintf("Unknown %%%%Orientation on line %d", psdoc->linecount);
  547.         }
  548.         else if (strncmp(psdoc->line, "%%PaperSize:", 12) == 0) {
  549.         /* DSC 2.0 comment */
  550.         stripline(psdoc->line);
  551.         if ( (p = strtok(psdoc->line+12, " \t")) != (char *)NULL ) {
  552.             if (strcmp(p, "(atend)") != 0) {
  553.               PSMEDIA *pm;
  554.               for (pm = paper_size; pm->name; pm++)
  555.             if (stricmp(pm->name, p) == 0) {
  556.                 psdoc->default_page_media = malloc(sizeof(PSMEDIA));
  557.                 if (!psdoc->default_page_media)
  558.                 return nomemory(__FILE__, __LINE__);
  559.                 psdoc->default_page_media->name = malloc(strlen(pm->name)+1);
  560.                 if (!psdoc->default_page_media->name)
  561.                 return nomemory(__FILE__, __LINE__);
  562.                 strcpy(psdoc->default_page_media->name, pm->name);
  563.                 psdoc->default_page_media->width = pm->width;
  564.                 psdoc->default_page_media->height = pm->height;
  565.                 break;    /* exit after match */
  566.             }
  567.                 if (psdoc->default_page_media->name == (char *)NULL)
  568.                     eprintf("Unknown %%%%PaperSize on line %d", psdoc->linecount);
  569.             }
  570.         }
  571.         else
  572.                 eprintf("Unknown %%%%PaperSize on line %d", psdoc->linecount);
  573.         }
  574.         else if (strncmp(psdoc->line, "%%DocumentMedia:", 16) == 0) {
  575.         stripline(psdoc->line);
  576.         if (strncmp(psdoc->line+17, "(atend)", 7) != 0) {
  577.             if (!dsc_document_media(psdoc))
  578.                     return nomemory(__FILE__, __LINE__);
  579.             readahead = TRUE;
  580.         }
  581.         }
  582.         psdoc->endcomments = ftell(psdoc->f);
  583.     }
  584.     return TRUE;
  585. }
  586.  
  587. static int
  588. dsc_preview(PSDOC *psdoc)
  589. {
  590.         psdoc->beginpreview = psdoc->endpreview = psdoc->position;
  591.     while ((psdoc->line[0]=='\r') || (psdoc->line[0]=='\n'))
  592.         getline(psdoc);    /* skip blank lines */
  593.     if (strncmp(psdoc->line, "%%BeginPreview:", 15) != 0) {
  594.             /* psdoc->beginpreview = psdoc->endpreview = 0; */
  595.         return TRUE;
  596.     }
  597.     while (getline(psdoc)) {
  598.         if (strncmp(psdoc->line, "%%EndPreview", 12) == 0) {
  599.         getline(psdoc);
  600.         psdoc->endpreview = psdoc->position;
  601.         return TRUE;
  602.         }
  603.     }
  604.     psdoc->endpreview = ftell(psdoc->f);
  605.     return TRUE;
  606. }
  607.  
  608. static int
  609. dsc_defaults(PSDOC *psdoc)
  610. {
  611.         psdoc->begindefaults = psdoc->enddefaults = psdoc->position;
  612.     while ((psdoc->line[0]=='\r') || (psdoc->line[0]=='\n'))
  613.         getline(psdoc);    /* skip blank lines */
  614.     if (strncmp(psdoc->line, "%%BeginDefaults", 15) != 0) {
  615.             psdoc->begindefaults = psdoc->enddefaults = 0;
  616.         return TRUE;
  617.     }
  618.     while (getline(psdoc)) {
  619.         if (strncmp(psdoc->line, "%%EndDefaults", 13) == 0) {
  620.         psdoc->enddefaults = ftell(psdoc->f);
  621.         getline(psdoc);
  622.         return TRUE;
  623.         }
  624.         else if (strncmp(psdoc->line, "%%PageMedia:", 12) == 0) {
  625.         PSMEDIA *media;
  626.         char name[PSLINELENGTH];
  627.         char *n;
  628.         stripline(psdoc->line);
  629.         dsc_text(psdoc->line+12, name, &n);
  630.         media = malloc(sizeof(PSMEDIA));
  631.         if (media == (PSMEDIA *)NULL)
  632.             return nomemory(__FILE__, __LINE__);
  633.         media->width = 0;
  634.         media->height = 0;
  635.         media->next = NULL;
  636.         media->name = malloc(strlen(name)+1);
  637.         if (media->name == (char *)NULL)
  638.             return nomemory(__FILE__, __LINE__);
  639.         strcpy(media->name, name);
  640.         psdoc->default_page_media = media;
  641.         /* set width and height from %%DocumentMedia: */
  642.         for (media=psdoc->document_media; media; media=media->next) {
  643.             if (strcmp(psdoc->default_page_media->name, media->name) == 0) {
  644.             psdoc->default_page_media->width  = media->width;
  645.             psdoc->default_page_media->height = media->height;
  646.             break;
  647.             }
  648.         }
  649.         }
  650.     }
  651.     psdoc->enddefaults = ftell(psdoc->f);
  652.     return TRUE;
  653. }
  654.  
  655. static int
  656. dsc_prolog(PSDOC *psdoc)
  657. {
  658.         psdoc->beginprolog = psdoc->endprolog = ftell(psdoc->f);
  659.     if (strncmp(psdoc->line, "%%BeginProlog", 13) != 0) {
  660.         if (dsc_nextsection(psdoc))
  661.         return TRUE;
  662.     }
  663.         psdoc->beginprolog = psdoc->endprolog = psdoc->position;
  664.     /* %%BeginProlog may not be present */
  665.     if (strncmp(psdoc->line, "%%EndProlog", 11) == 0) {
  666.         getline(psdoc);
  667.         psdoc->endprolog = psdoc->position;
  668.         return TRUE;
  669.     }
  670.     while (getline(psdoc)) {
  671.         if (strncmp(psdoc->line, "%%BeginProlog", 13) == 0) {
  672.         psdoc->beginprolog = psdoc->position;
  673.         }
  674.         else if (strncmp(psdoc->line, "%%EndProlog", 11) == 0) {
  675.         getline(psdoc);
  676.         psdoc->endprolog = psdoc->position;
  677.         return TRUE;
  678.         }
  679.         else if (dsc_nextsection(psdoc)) {
  680.         psdoc->endprolog = psdoc->position;
  681.         return TRUE;
  682.         }
  683.     }
  684.     psdoc->endprolog = ftell(psdoc->f);
  685.     return TRUE;
  686. }
  687.  
  688. static int
  689. dsc_setup(PSDOC *psdoc)
  690. {
  691.         psdoc->beginsetup = psdoc->endsetup = psdoc->position;
  692.     while ((psdoc->line[0]=='\r') || (psdoc->line[0]=='\n'))
  693.         getline(psdoc);    /* skip blank lines */
  694.     if (strncmp(psdoc->line, "%%BeginSetup", 12) != 0)
  695.         return TRUE;
  696.     while (getline(psdoc)) {
  697.         if (strncmp(psdoc->line, "%%BeginSetup", 12) == 0) {
  698.             psdoc->beginsetup = psdoc->position;
  699.         }
  700.         else if (strncmp(psdoc->line, "%%EndSetup", 10) == 0) {
  701.         getline(psdoc);
  702.         psdoc->endsetup = psdoc->position;
  703.         return TRUE;
  704.         }
  705.         else if (dsc_nextsection(psdoc)) {
  706.         psdoc->endsetup = psdoc->position;
  707.         return TRUE;
  708.         }
  709. /* should look for %%BeginPaperSize: */
  710.     }
  711.     psdoc->endsetup = ftell(psdoc->f);
  712.     return TRUE;
  713. }
  714.  
  715. static PSPAGE *
  716. dsc_page(PSDOC *psdoc, PSPAGE *pspage, long position)
  717. {
  718. char *n;
  719. char buf[PSLINELENGTH];
  720.     if (pspage != (PSPAGE *)NULL) {
  721.         pspage->end = position;
  722.         /* add a new page */
  723.         pspage->next = malloc(sizeof(PSPAGE));
  724.         if (pspage->next == (PSPAGE *)NULL)
  725.             return (PSPAGE *)nomemory(__FILE__, __LINE__);
  726.         pspage = pspage->next;
  727.     }
  728.     else {
  729.         /* add initial page */
  730.         psdoc->page_list = malloc(sizeof(PSPAGE));
  731.         if (psdoc->page_list == (PSPAGE *)NULL)
  732.         return (PSPAGE *)nomemory(__FILE__, __LINE__);
  733.         pspage = psdoc->page_list;
  734.     }
  735.     pspage->begin = position;
  736.     pspage->end = position;
  737.     pspage->label = (char *)NULL;
  738.     pspage->ordinal = 0;
  739.     pspage->next = (PSPAGE *)NULL;
  740.     psdoc->numpages++;
  741.     dsc_text(psdoc->line+7, buf, &n);
  742.     pspage->label = malloc(strlen(buf)+1);
  743.     if (pspage->label == (char *)NULL)
  744.         return (PSPAGE *)nomemory(__FILE__, __LINE__);
  745.     strcpy(pspage->label, buf);
  746.     if (*n == 0) {
  747.         eprintf("Unknown %%%%Page on line %d", psdoc->linecount);
  748.     }
  749.     pspage->ordinal = atoi(n);
  750.     return pspage;
  751. }
  752.  
  753. static int
  754. dsc_pages(PSDOC *psdoc)
  755. {
  756. long position;
  757. PSPAGE *pspage;
  758.     pspage = NULL;
  759.     psdoc->numpages = 0;
  760.     position = ftell(psdoc->f);
  761.     if (strncmp(psdoc->line, "%%Page:", 7) == 0) {
  762.         pspage = dsc_page(psdoc, pspage, psdoc->endsetup);
  763.         if (pspage == (PSPAGE *)NULL)
  764.             return FALSE;
  765.     }
  766.  
  767.     while (getline(psdoc)) {
  768.         if (strncmp(psdoc->line, "%%Page:", 7) == 0) {
  769.             pspage = dsc_page(psdoc, pspage, position);
  770.         if (pspage == (PSPAGE *)NULL)
  771.             return FALSE;
  772.         }
  773.         else if (strncmp(psdoc->line, "%%Trailer", 9) == 0) {
  774.         if (pspage)
  775.             pspage->end = position;
  776.         psdoc->begintrailer = position;
  777.         return TRUE;
  778.         }
  779.         position = ftell(psdoc->f);
  780.     }
  781.  
  782.     position = ftell(psdoc->f);
  783.     if (pspage)
  784.         pspage->end = position;
  785.     psdoc->begintrailer = position;
  786.     return TRUE;
  787. }
  788.  
  789. /* fix up things not known until after trailer processed */
  790. static dsc_fixup(PSDOC *psdoc)
  791. {
  792. PSPAGE *pspage;
  793. int i;
  794.     if (psdoc->numpages) {
  795.         psdoc->pages = malloc(sizeof(PSPAGE) * psdoc->numpages);
  796.         if (psdoc->pages == (PSPAGE *)NULL)
  797.             return nomemory(__FILE__, __LINE__);
  798.         for (pspage = psdoc->page_list, i=0; pspage != (PSPAGE *)NULL; 
  799.             pspage = pspage->next, i++) {
  800.             psdoc->pages[i].begin = pspage->begin;
  801.             psdoc->pages[i].end = pspage->end;
  802.             psdoc->pages[i].label = pspage->label;
  803.             psdoc->pages[i].ordinal = pspage->ordinal;
  804.         }
  805.     }
  806.     if (psdoc->dscpages == ATEND) {
  807.         eprintf("Missing %%%%Pages comment");
  808.         psdoc->dscpages = psdoc->numpages;
  809.     }
  810.     if (psdoc->dscpages && (psdoc->numpages != psdoc->dscpages)) {
  811.         eprintf("%%%%Pages comment does not match number of pages");
  812.         psdoc->dscpages = psdoc->numpages;
  813.     }
  814.     if (psdoc->pageorder == ATEND) {
  815.         eprintf("Missing %%%%PageOrder comment");
  816.         psdoc->pageorder = NONE;
  817.     }
  818.     if (psdoc->orientation == ATEND) {
  819.         eprintf("Missing %%%%Orientation comment");
  820.         psdoc->orientation = NONE;
  821.     }
  822.     if ( (psdoc->default_page_media == NULL) && 
  823.          (psdoc->document_media != NULL) ) {
  824.         /* make default_page_media = first media of %%DocumentMedia */
  825.         psdoc->default_page_media = malloc(sizeof(PSMEDIA));
  826.         if (!psdoc->default_page_media)
  827.         return nomemory(__FILE__, __LINE__);
  828.         psdoc->default_page_media->name = malloc(strlen(psdoc->document_media->name)+1);
  829.         if (!psdoc->default_page_media->name)
  830.         return nomemory(__FILE__, __LINE__);
  831.         strcpy(psdoc->default_page_media->name, psdoc->document_media->name);
  832.         psdoc->default_page_media->width  = psdoc->document_media->width;
  833.         psdoc->default_page_media->height = psdoc->document_media->height;
  834.     }
  835.     if ( (psdoc->default_page_media != NULL) &&
  836.              ((psdoc->default_page_media->width==0) ||
  837.               (psdoc->default_page_media->height==0)) ) {
  838.         /* %%DocumentMedia occurred after %%PageMedia */
  839.         PSMEDIA *media;
  840.         for (media=psdoc->document_media; media; media=media->next) {
  841.         if (strcmp(psdoc->default_page_media->name, media->name) == 0) {
  842.             psdoc->default_page_media->width  = media->width;
  843.             psdoc->default_page_media->height = media->height;
  844.             break;
  845.         }
  846.         }
  847.     }
  848.     return TRUE;
  849. }
  850.  
  851. static int
  852. dsc_trailer(PSDOC *psdoc)
  853. {
  854. int readahead = FALSE;
  855. char *p;
  856.     /* psdoc->begintrailer has already been set */
  857.     while (readahead || getline(psdoc)) {
  858.         readahead = FALSE;
  859.         if (strncmp(psdoc->line, "%%EOF", 5) == 0) {
  860.         break;
  861.         }
  862.         else if (strncmp(psdoc->line, "%%BoundingBox:", 14) == 0) {
  863.         if ((psdoc->bbox.valid == ATEND) || (psdoc->bbox.valid == FALSE)) {
  864.             if (sscanf(psdoc->line + 14, "%d %d %d %d", &psdoc->bbox.llx, &psdoc->bbox.lly,
  865.                 &psdoc->bbox.urx, &psdoc->bbox.ury) == 4)
  866.             psdoc->bbox.valid = TRUE;
  867.             else {
  868.                 eprintf("Invalid %%%%BoundingBox on line %d", psdoc->linecount);
  869.                 return FALSE;
  870.             }
  871.         }
  872.         else
  873.             eprintf("Duplicate %%%%BoundingBox on line %d", psdoc->linecount);
  874.         }
  875.         else if (strncmp(psdoc->line, "%%Pages:", 8) == 0) {
  876.         if ( (psdoc->dscpages == ATEND) || (psdoc->dscpages == NONE) ) {
  877.             if (sscanf(psdoc->line + 8, "%d", &psdoc->dscpages) != 1) {
  878.                 eprintf("Invalid %%%%Pages on line %d", psdoc->linecount);
  879.                 return FALSE;
  880.             }
  881.         }
  882.         }
  883.         else if (strncmp(psdoc->line, "%%PageOrder:", 12) == 0) {
  884.         stripline(psdoc->line);
  885.         if (psdoc->pageorder == ATEND) {
  886.             if ( (p = strtok(psdoc->line+12, " \t")) != (char *)NULL ) {
  887.             if (strcmp(p, "Ascend") == 0)
  888.                 psdoc->pageorder = ASCEND;
  889.             else if (strcmp(p, "Descend") == 0)
  890.                 psdoc->pageorder = DESCEND;
  891.             else if (strcmp(p, "Special") == 0)
  892.                 psdoc->pageorder = SPECIAL;
  893.             else
  894.                 eprintf("Unknown %%%%PageOrder on line %d", psdoc->linecount);
  895.             }
  896.             else
  897.                 eprintf("Unknown %%%%PageOrder on line %d", psdoc->linecount);
  898.         }
  899.         else
  900.                 eprintf("Duplicate %%%%PageOrder on line %d", psdoc->linecount);
  901.         }
  902.         else if (strncmp(psdoc->line, "%%Orientation:", 14) == 0) {
  903.         stripline(psdoc->line);
  904.         if (psdoc->orientation == ATEND) {
  905.             if ( (p = strtok(psdoc->line+14, " \t")) != (char *)NULL ) {
  906.             if (strcmp(p, "Portrait") == 0)
  907.                 psdoc->orientation = PORTRAIT;
  908.             else if (strcmp(p, "Landscape") == 0)
  909.                 psdoc->orientation = LANDSCAPE;
  910.             else
  911.                 eprintf("Unknown %%%%Orientation on line %d", psdoc->linecount);
  912.             }
  913.             else
  914.                 eprintf("Unknown %%%%Orientation on line %d", psdoc->linecount);
  915.         }
  916.         else
  917.             eprintf("Duplicate %%%%Orientation on line %d", psdoc->linecount);
  918.         }
  919.         else if (strncmp(psdoc->line, "%%PaperSize:", 12) == 0) {
  920.         /* DSC 2.0 comment */
  921.         stripline(psdoc->line);
  922.         if ( (p = strtok(psdoc->line+12, " \t")) != (char *)NULL ) {
  923.             PSMEDIA *pm;
  924.             for (pm = paper_size; pm->name; pm++)
  925.             if (stricmp(pm->name, p) == 0) {
  926.                 psdoc->default_page_media = malloc(sizeof(PSMEDIA));
  927.                 if (!psdoc->default_page_media)
  928.                 return nomemory(__FILE__, __LINE__);
  929.                 psdoc->default_page_media->name = malloc(strlen(pm->name)+1);
  930.                 if (!psdoc->default_page_media->name)
  931.                 return nomemory(__FILE__, __LINE__);
  932.                 strcpy(psdoc->default_page_media->name, pm->name);
  933.                 psdoc->default_page_media->width = pm->width;
  934.                 psdoc->default_page_media->height = pm->height;
  935.             }
  936.             if (psdoc->default_page_media->name == (char *)NULL)
  937.                 eprintf("Unknown %%%%PaperSize on line %d", psdoc->linecount);
  938.         }
  939.         else
  940.                 eprintf("Unknown %%%%PaperSize on line %d", psdoc->linecount);
  941.         }
  942.         else if (strncmp(psdoc->line, "%%DocumentMedia:", 16) == 0) {
  943.         if (psdoc->document_media == (PSMEDIA *)NULL) {
  944.             if (!dsc_document_media(psdoc))
  945.                     return nomemory(__FILE__, __LINE__);
  946.             readahead = TRUE;
  947.         }
  948.         }
  949.     }
  950.     psdoc->endtrailer = ftell(psdoc->f);
  951.     return TRUE;
  952. }
  953.  
  954. static unsigned long dsc_arch = 0x00000001;
  955.  
  956. /* change byte order if architecture is big-endian */
  957. DWORD
  958. reorder_dword(DWORD val)
  959. {
  960.     if (*((char *)(&dsc_arch)))
  961.         return val;    /* little endian machine */
  962.     else
  963.     return ((val&0xff) << 24) | ((val&0xff00) << 8)
  964.              | ((val&0xff0000L) >> 8) | ((val>>24)&0xff);
  965. }
  966.  
  967. /* change byte order if architecture is big-endian */
  968. WORD
  969. reorder_word(WORD val)
  970. {
  971.     if (*((char *)(&dsc_arch)))
  972.         return val;    /* little endian machine */
  973.     else
  974.     return (WORD) ((val&0xff) << 8) | ((val&0xff00) >> 8);
  975. }
  976.  
  977. /* DOS EPS header reading */
  978. static int
  979. dsc_read_doseps(PSDOC *psdoc)
  980. {
  981. DOSEPS doseps;
  982.     fread(doseps.id, 1, 4, psdoc->f);
  983.     if (! ((doseps.id[0]==0xc5) && (doseps.id[1]==0xd0) 
  984.         && (doseps.id[2]==0xd3) && (doseps.id[3]==0xc6)) ) {
  985.         /* id is "EPSF" with bit 7 set */
  986.         rewind(psdoc->f);
  987.         return TRUE;     /* OK */
  988.     }
  989.     fread(&doseps.ps_begin,    4, 1, psdoc->f);    /* PS offset */
  990.     doseps.ps_begin = (unsigned long)reorder_dword(doseps.ps_begin);
  991.     fread(&doseps.ps_length,   4, 1, psdoc->f);    /* PS length */
  992.     doseps.ps_length = (unsigned long)reorder_dword(doseps.ps_length);
  993.     fread(&doseps.mf_begin,    4, 1, psdoc->f);    /* Metafile offset */
  994.     doseps.mf_begin = (unsigned long)reorder_dword(doseps.mf_begin);
  995.     fread(&doseps.mf_length,   4, 1, psdoc->f);    /* Metafile length */
  996.     doseps.mf_length = (unsigned long)reorder_dword(doseps.mf_length);
  997.     fread(&doseps.tiff_begin,  4, 1, psdoc->f);    /* TIFF offset */
  998.     doseps.tiff_begin = (unsigned long)reorder_dword(doseps.tiff_begin);
  999.     fread(&doseps.tiff_length, 4, 1, psdoc->f);    /* TIFF length */
  1000.     doseps.tiff_length = (unsigned long)reorder_dword(doseps.tiff_length);
  1001.     fread(&doseps.checksum,    2, 1, psdoc->f);
  1002.         doseps.checksum = (unsigned short)reorder_word(doseps.checksum);
  1003.     fseek(psdoc->f, doseps.ps_begin, SEEK_SET);    /* seek to PS section */
  1004.     psdoc->doseps = malloc(sizeof(DOSEPS));
  1005.     if (psdoc->doseps == (DOSEPS *)NULL)
  1006.         return nomemory(__FILE__, __LINE__);
  1007.     *psdoc->doseps = doseps;
  1008.     psdoc->enddoseps = doseps.ps_begin + doseps.ps_length;
  1009.     return TRUE;
  1010. }
  1011.  
  1012. /*********************************************************/
  1013. /* global functions */
  1014.  
  1015. /* file must have been opened in binary mode */
  1016. PSDOC *
  1017. dsc_scan_file(FILE *f)
  1018. {
  1019. PSDOC *psdoc;
  1020. char line[PSLINELENGTH];
  1021.     if ((psdoc = malloc(sizeof(PSDOC))) == (PSDOC *)NULL) {
  1022.         nomemory(__FILE__, __LINE__);
  1023.         return (PSDOC *)NULL;
  1024.     }
  1025.     memset(psdoc, 0, sizeof(PSDOC));
  1026.     /* initialise internal scratch items */
  1027.     psdoc->f = f;
  1028.     psdoc->position = 0;
  1029.     psdoc->line = line;
  1030.     psdoc->linecount = 0;
  1031.     psdoc->enddoseps = 0;
  1032.     rewind(psdoc->f);
  1033.     if (!dsc_read_doseps(psdoc))
  1034.        return cleanup(psdoc);
  1035.     if (!getline(psdoc))
  1036.        return cleanup(psdoc);
  1037.     /* since some of these scanning routines may read one line past */
  1038.     /* the end of the section, all scanning routines must do so */
  1039.     if (!dsc_comments(psdoc))
  1040.        return cleanup(psdoc);
  1041.     if (!dsc_preview(psdoc))
  1042.        return cleanup(psdoc);
  1043.     if (!dsc_defaults(psdoc))
  1044.        return cleanup(psdoc);
  1045.     if (!dsc_prolog(psdoc))
  1046.        return cleanup(psdoc);
  1047.     if (!dsc_setup(psdoc))
  1048.        return cleanup(psdoc);
  1049.     if (!dsc_pages(psdoc))
  1050.        return cleanup(psdoc);
  1051.     if (!dsc_trailer(psdoc))
  1052.        return cleanup(psdoc);
  1053.     if (!dsc_fixup(psdoc))
  1054.        return cleanup(psdoc);
  1055.     /* clear internal items */
  1056.     psdoc->f = NULL;
  1057.     psdoc->position = 0;
  1058.     psdoc->line = NULL;
  1059.     psdoc->linecount = 0;
  1060.     psdoc->enddoseps = 0;
  1061.     return psdoc;
  1062. }
  1063.  
  1064. void
  1065. dsc_scan_clean(PSDOC *psdoc)
  1066. {
  1067.     cleanup(psdoc);
  1068. }
  1069.  
  1070. void
  1071. dsc_scan_debug(int flag)
  1072. {
  1073.     debug = flag;
  1074. }
  1075.  
  1076. /* copy from file f to file tofile, between begin and end */
  1077. /* if comment given, stop when comment found */
  1078. char *
  1079. dsc_copy(FILE *f, FILE *tofile, long begin, long end, char *comment)
  1080. {
  1081. char linebuf[PSLINELENGTH];
  1082.     if (begin >= 0)
  1083.         fseek(f, begin, SEEK_SET);
  1084.     while (ftell(f) < end) {
  1085.         fgets(linebuf, sizeof(linebuf), f);
  1086.         if (comment && (strncmp(linebuf, comment, sizeof(comment))==0)) {
  1087.         char *p;
  1088.         if ((p = malloc(strlen(linebuf)+1)) == (char *)NULL) {
  1089.             nomemory(__FILE__, __LINE__);
  1090.             return (char *)NULL;
  1091.         }
  1092.         strcpy(p, linebuf);
  1093.         return p;
  1094.         }
  1095.         fputs(linebuf, tofile);
  1096.         /* copy binary sections */
  1097.         if (strncmp(linebuf, "%%BeginBinary:",14)==0) {
  1098.         long count = 0;
  1099.         int read;
  1100.         char buf[1024];
  1101.         if (sscanf(linebuf+14, "%ld", &count) != 1)
  1102.             count = 0;
  1103.         while (count) {
  1104.             read = fread(buf, 1, sizeof(buf), f);
  1105.             count -= read;
  1106.             if (read == 0)
  1107.                 count = 0;
  1108.             else
  1109.             fwrite(buf, 1, read, tofile);
  1110.         }
  1111.         }
  1112.         if (strncmp(linebuf, "%%BeginData:",12)==0) {
  1113.             long count;
  1114.             int read;
  1115.             char buf[PSLINELENGTH];
  1116.             if (sscanf(linebuf+12, "%ld %*s %s", &count, buf) != 2)
  1117.                 count = 0;
  1118.             if (strncmp(buf, "Lines", 5) == 0) {
  1119.                 while (count) {
  1120.                     count--;
  1121.             do {    /* handle antisocial PostScript with excessively long lines */
  1122.                 if (fgets(buf, sizeof(buf), f) == (char *)NULL) {
  1123.                     count = 0;
  1124.                 buf[0] = '\0';
  1125.                 }
  1126.                 else
  1127.                     fputs(buf, tofile);
  1128.             } while ( (strlen(buf) == sizeof(buf)-1) &&
  1129.                       (buf[sizeof(buf)-2] != '\n') );
  1130.                 }
  1131.             }
  1132.             else {
  1133.             while (count) {
  1134.             read = fread(buf, 1, sizeof(buf), f);
  1135.             count -= read;
  1136.             if (read == 0)
  1137.                 count = 0;
  1138.                 else
  1139.                 fwrite(buf, 1, read, tofile);
  1140.             }
  1141.             }
  1142.         }
  1143.     }
  1144.     return (char *)NULL;
  1145. }
  1146.